use crate::app::event::Event;
use crate::app::state::{Consumed, SessionHelper, SessionState};
use crate::app::DynError;
use crate::sketchbook::data_structs::{ChangeIdData, DynPropertyData, StatPropertyData};
use crate::sketchbook::event_utils::{
make_refresh_event, make_reversible, mk_dyn_prop_event, mk_dyn_prop_state_change,
mk_stat_prop_event, mk_stat_prop_state_change,
};
use crate::sketchbook::ids::{DynPropertyId, StatPropertyId, VarId};
use crate::sketchbook::properties::dynamic_props::SimpleDynPropertyType;
use crate::sketchbook::properties::static_props::SimpleStatPropertyType;
use crate::sketchbook::properties::{DynProperty, PropertyManager, StatProperty};
use crate::sketchbook::JsonSerde;
const DYNAMIC_PATH: &str = "dynamic";
const STATIC_PATH: &str = "static";
const ADD_PATH: &str = "add";
const ADD_DEFAULT_PATH: &str = "add_default";
const REMOVE_PATH: &str = "remove";
const SET_ID_PATH: &str = "set_id";
const SET_VAR_ID_EVERYWHERE_PATH: &str = "set_var_id_everywhere";
const SET_CONTENT_PATH: &str = "set_content";
const GET_ALL_DYNAMIC_PATH: &str = "get_all_dynamic";
const GET_ALL_STATIC_PATH: &str = "get_all_static";
impl SessionHelper for PropertyManager {}
impl SessionState for PropertyManager {
fn perform_event(&mut self, event: &Event, at_path: &[&str]) -> Result<Consumed, DynError> {
let component_name = "properties";
match at_path.first() {
Some(&DYNAMIC_PATH) => {
let at_path = &at_path[1..];
if Self::starts_with(ADD_DEFAULT_PATH, at_path).is_some() {
Self::assert_path_length(at_path, 1, component_name)?;
self.event_add_default_dynamic(event)
} else if Self::starts_with(ADD_PATH, at_path).is_some() {
Self::assert_path_length(at_path, 1, component_name)?;
self.event_add_dynamic(event)
} else {
Self::assert_path_length(at_path, 2, component_name)?;
let prop_id_str = at_path.first().unwrap();
let prop_id = self.get_dyn_prop_id(prop_id_str)?;
self.event_modify_dynamic(event, &at_path[1..], prop_id)
}
}
Some(&STATIC_PATH) => {
let at_path = &at_path[1..];
if Self::starts_with(ADD_DEFAULT_PATH, at_path).is_some() {
Self::assert_path_length(at_path, 1, component_name)?;
self.event_add_default_static(event)
} else if Self::starts_with(ADD_PATH, at_path).is_some() {
Self::assert_path_length(at_path, 1, component_name)?;
self.event_add_static(event)
} else if Self::starts_with(SET_VAR_ID_EVERYWHERE_PATH, at_path).is_some() {
Self::assert_path_length(at_path, 1, component_name)?;
let payload = Self::clone_payload_str(event, component_name)?;
let change_id_data = ChangeIdData::from_json_str(&payload)?;
let old_var_id = VarId::new(&change_id_data.original_id)?;
let new_var_id = VarId::new(&change_id_data.new_id)?;
for (_, prop) in self.stat_properties.iter_mut() {
let _ = prop.set_var_id_if_present(old_var_id.clone(), new_var_id.clone());
}
self.make_generated_reg_prop_ids_consistent();
let mut properties_list: Vec<StatPropertyData> = self
.stat_properties
.iter()
.map(|(id, prop)| StatPropertyData::from_property(id, prop))
.collect();
properties_list.sort_by(|a, b| a.id.cmp(&b.id));
let state_change = Event {
path: vec![
"sketch".to_string(),
"properties".to_string(),
"static".to_string(),
"set_var_id_everywhere".to_string(),
],
payload: Some(serde_json::to_string(&properties_list)?),
};
let reverse_id_change_data =
ChangeIdData::new(&change_id_data.new_id, &change_id_data.original_id);
let payload = reverse_id_change_data.to_json_str();
let reverse_event =
mk_stat_prop_event(&[SET_VAR_ID_EVERYWHERE_PATH], Some(&payload));
Ok(make_reversible(state_change, event, reverse_event))
} else {
Self::assert_path_length(at_path, 2, component_name)?;
let prop_id_str = at_path.first().unwrap();
let prop_id = self.get_stat_prop_id(prop_id_str)?;
self.event_modify_static(event, &at_path[1..], prop_id)
}
}
_ => Self::invalid_path_error_generic(at_path),
}
}
fn refresh(&self, full_path: &[String], at_path: &[&str]) -> Result<Event, DynError> {
let component_name = "properties";
match at_path.first() {
Some(&GET_ALL_DYNAMIC_PATH) => {
Self::assert_path_length(at_path, 1, component_name)?;
let mut properties_list: Vec<DynPropertyData> = self
.dyn_properties
.iter()
.map(|(id, prop)| DynPropertyData::from_property(id, prop))
.collect();
properties_list.sort_by(|a, b| a.id.cmp(&b.id));
make_refresh_event(full_path, properties_list)
}
Some(&GET_ALL_STATIC_PATH) => {
Self::assert_path_length(at_path, 1, component_name)?;
let mut properties_list: Vec<StatPropertyData> = self
.stat_properties
.iter()
.map(|(id, prop)| StatPropertyData::from_property(id, prop))
.collect();
properties_list.sort_by(|a, b| a.id.cmp(&b.id));
make_refresh_event(full_path, properties_list)
}
_ => Self::invalid_path_error_generic(at_path),
}
}
}
impl PropertyManager {
pub(super) fn event_add_dynamic(&mut self, event: &Event) -> Result<Consumed, DynError> {
let component_name = "properties/dynamic";
let payload = Self::clone_payload_str(event, component_name)?;
let prop_data = DynPropertyData::from_json_str(payload.as_str())?;
let property = prop_data.to_property()?;
self.add_dynamic_by_str(&prop_data.id, property)?;
let reverse_event = mk_dyn_prop_event(&[&prop_data.id, "remove"], None);
Ok(make_reversible(event.clone(), event, reverse_event))
}
pub(super) fn event_add_default_dynamic(
&mut self,
event: &Event,
) -> Result<Consumed, DynError> {
let component_name = "properties/dynamic";
let payload = Self::clone_payload_str(event, component_name)?;
let prop_type = SimpleDynPropertyType::from_json_str(payload.as_str())?;
let property = DynProperty::default(prop_type);
let prop_id = self.generate_dyn_property_id("dynamic", Some(1));
let prop_data = DynPropertyData::from_property(&prop_id, &property);
self.add_dynamic_by_str(&prop_data.id, property)?;
let state_change = mk_dyn_prop_state_change(&["add"], &prop_data);
let reverse_event = mk_dyn_prop_event(&[&prop_data.id, "remove"], None);
Ok(make_reversible(state_change, event, reverse_event))
}
pub(super) fn event_modify_dynamic(
&mut self,
event: &Event,
at_path: &[&str],
prop_id: DynPropertyId,
) -> Result<Consumed, DynError> {
let component_name = "properties/dynamic";
if Self::starts_with(REMOVE_PATH, at_path).is_some() {
Self::assert_payload_empty(event, component_name)?;
let original_prop = self.get_dyn_prop(&prop_id)?.clone();
let prop_data = DynPropertyData::from_property(&prop_id, &original_prop);
self.remove_dynamic(&prop_id)?;
let state_change = mk_dyn_prop_state_change(&["remove"], &prop_data);
let payload = prop_data.to_json_str();
let reverse_event = mk_dyn_prop_event(&["add"], Some(&payload));
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_ID_PATH, at_path).is_some() {
let new_id = Self::clone_payload_str(event, component_name)?;
if prop_id.as_str() == new_id.as_str() {
return Ok(Consumed::NoChange);
}
self.set_dyn_id_by_str(prop_id.as_str(), new_id.as_str())?;
let id_change_data = ChangeIdData::new(prop_id.as_str(), new_id.as_str());
let state_change = mk_dyn_prop_state_change(&["set_id"], &id_change_data);
let payload = prop_id.as_str();
let reverse_event = mk_dyn_prop_event(&[new_id.as_str(), "set_id"], Some(payload));
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_CONTENT_PATH, at_path).is_some() {
let payload = Self::clone_payload_str(event, component_name)?;
let new_property_data = DynPropertyData::from_json_str(&payload)?;
let new_property = new_property_data.to_property()?;
let orig_property = self.get_dyn_prop(&prop_id)?;
if orig_property == &new_property {
return Ok(Consumed::NoChange);
}
let orig_prop_data = DynPropertyData::from_property(&prop_id, orig_property);
self.swap_dyn_content(&prop_id, new_property)?;
let state_change = mk_dyn_prop_state_change(&["set_content"], &new_property_data);
let reverse_at_path = [prop_id.as_str(), "set_content"];
let payload = orig_prop_data.to_json_str();
let reverse_event = mk_dyn_prop_event(&reverse_at_path, Some(&payload));
Ok(make_reversible(state_change, event, reverse_event))
} else {
Self::invalid_path_error_specific(at_path, component_name)
}
}
}
impl PropertyManager {
pub(super) fn event_add_static(&mut self, event: &Event) -> Result<Consumed, DynError> {
let component_name = "properties/static";
let payload = Self::clone_payload_str(event, component_name)?;
let prop_data = StatPropertyData::from_json_str(payload.as_str())?;
let property = prop_data.to_property()?;
self.add_static_by_str(&prop_data.id, property)?;
let reverse_event = mk_stat_prop_event(&[&prop_data.id, "remove"], None);
Ok(make_reversible(event.clone(), event, reverse_event))
}
pub(super) fn event_add_default_static(&mut self, event: &Event) -> Result<Consumed, DynError> {
let component_name = "properties/static";
let payload = Self::clone_payload_str(event, component_name)?;
let prop_type = SimpleStatPropertyType::from_json_str(payload.as_str())?;
let property = StatProperty::default(prop_type);
let prop_id = self.generate_stat_property_id("static", Some(1));
let prop_data = StatPropertyData::from_property(&prop_id, &property);
self.add_static_by_str(&prop_data.id, property)?;
let state_change = mk_stat_prop_state_change(&["add"], &prop_data);
let reverse_event = mk_stat_prop_event(&[&prop_data.id, "remove"], None);
Ok(make_reversible(state_change, event, reverse_event))
}
pub(super) fn event_modify_static(
&mut self,
event: &Event,
at_path: &[&str],
prop_id: StatPropertyId,
) -> Result<Consumed, DynError> {
let component_name = "properties/static";
if Self::starts_with(REMOVE_PATH, at_path).is_some() {
Self::assert_payload_empty(event, component_name)?;
let original_prop = self.get_stat_prop(&prop_id)?.clone();
let prop_data = StatPropertyData::from_property(&prop_id, &original_prop);
self.remove_static(&prop_id)?;
let state_change = mk_stat_prop_state_change(&["remove"], &prop_data);
let payload = prop_data.to_json_str();
let reverse_event = mk_stat_prop_event(&["add"], Some(&payload));
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_ID_PATH, at_path).is_some() {
let new_id = Self::clone_payload_str(event, component_name)?;
if prop_id.as_str() == new_id.as_str() {
return Ok(Consumed::NoChange);
}
self.set_stat_id_by_str(prop_id.as_str(), new_id.as_str())?;
let id_change_data = ChangeIdData::new(prop_id.as_str(), new_id.as_str());
let state_change = mk_stat_prop_state_change(&["set_id"], &id_change_data);
let payload = prop_id.as_str();
let reverse_event = mk_stat_prop_event(&[new_id.as_str(), "set_id"], Some(payload));
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_CONTENT_PATH, at_path).is_some() {
let payload = Self::clone_payload_str(event, component_name)?;
let new_property_data = StatPropertyData::from_json_str(&payload)?;
let new_property = new_property_data.to_property()?;
let orig_property = self.get_stat_prop(&prop_id)?;
if orig_property == &new_property {
return Ok(Consumed::NoChange);
}
let orig_prop_data = StatPropertyData::from_property(&prop_id, orig_property);
self.swap_stat_content(&prop_id, new_property)?;
let state_change = mk_stat_prop_state_change(&["set_content"], &new_property_data);
let reverse_at_path = [prop_id.as_str(), "set_content"];
let payload = orig_prop_data.to_json_str();
let reverse_event = mk_stat_prop_event(&reverse_at_path, Some(&payload));
Ok(make_reversible(state_change, event, reverse_event))
} else {
Self::invalid_path_error_specific(at_path, component_name)
}
}
}